﻿// <copyright file="CsrfSettings.cs" company="Barry Dorrans">
// Copyright (c) 2008 All Right Reserved, Barry Dorrans
//
// This source is subject to the Microsoft Permissive License.
// Please see the License.txt file for more information.
// All other rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// </copyright>
// <author>Barry Dorrans</author>
// <email>barryd@idunno.org</email>
// <date>2008-12-01</date>
// <summary>Configuration settings for the CSRF module.</summary>

namespace Idunno.AntiCsrf.Configuration
{
    using System;
    using System.Configuration;
    
    /// <summary>
    /// Configuration settings for the CSRF module.
    /// </summary>
    public sealed class CsrfSettings : ConfigurationSection
    {
        /// <summary>
        /// The configuration attribute for the cookie name.
        /// </summary>
        private const string CookieNameConfigurationKey = "cookieName";
        
        /// <summary>
        /// The configuration attribute for the form field name.
        /// </summary>
        private const string FromFieldNameConfigurationKey = "formFieldName";

        /// <summary>
        /// The configuration attribute for the action to take when a CSRF attempt is detected.
        /// </summary>
        private const string DetectionResultConfigurationKey = "detectionResult";

        /// <summary>
        /// The configuration attribute for the error page to redirect to if the detection result is configured to redirect.
        /// </summary>
        private const string ErrorPageConfigurationKey = "errorPage";

        /// <summary>
        /// The configuration attribute for the lock to session settings.
        /// </summary>
        private const string SessionLockedConfigurationKey = "sessionLocked";

        /// <summary>
        /// The default value for the cookie name.
        /// </summary>
        private const string CookieNameDefaultValue = "__CSRFCOOKIE";
        
        /// <summary>
        /// The default value for the form name.
        /// </summary>
        private const string FormNameDefaultValue = "__CSRFTOKEN";

        /// <summary>
        /// The default value for the detection result.
        /// </summary>
        private const string DetectionResultDefaultValue = "RaiseException";

        /// <summary>
        /// The CSRF settings.
        /// </summary>
        private static CsrfSettings settings =
            ConfigurationManager.GetSection("csrfSettings") as CsrfSettings;

        /// <summary>
        /// Gets the CSRF Settings.
        /// </summary>
        /// <value>The CSRF Settings.</value>
        public static CsrfSettings Settings
        {
            get
            {
                // If the configuration setting is not present create one with the default values.
                if (settings == null)
                {
                    settings = new CsrfSettings
                                   {
                                       CookieName = CookieNameDefaultValue,
                                       FormFieldName = FormNameDefaultValue,
                                       DetectionResult = DetectionResult.RaiseException
                                   };
                }

                return settings;
            }
        }

        /// <summary>
        /// Gets or sets the name of the cookie used to hold the CSRF token.
        /// </summary>
        /// <value>The name of the cookie used to hold the CSRF token.</value>
        [ConfigurationProperty(CookieNameConfigurationKey, DefaultValue = CookieNameDefaultValue)]     
        public string CookieName
        {
            get
            {
                return (string)base[CookieNameConfigurationKey];
            }

            set
            {
                base[CookieNameConfigurationKey] = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the tokens should additionally be locked
        /// to the current session.
        /// </summary>
        /// <value>True if the CSRF token should be linked to the current session, otherwise false.</value>
        [ConfigurationProperty(SessionLockedConfigurationKey, DefaultValue = false)]
        public bool SessionLocked
        {
            get
            {
                return (bool)base[SessionLockedConfigurationKey];
            }

            set
            {
                base[SessionLockedConfigurationKey] = value;
            }
        }

        /// <summary>
        /// Gets or sets the name of the form field used to hold the CSRF token.
        /// </summary>
        /// <value>The name of the form field used to hold the CSRF token.</value>
        [ConfigurationProperty(FromFieldNameConfigurationKey, DefaultValue = FormNameDefaultValue)]
        public string FormFieldName
        {
            get
            {
                return (string)base[FromFieldNameConfigurationKey];
            }

            set
            {
                base[FromFieldNameConfigurationKey] = value;
            }
        }

        /// <summary>
        /// Gets or sets the operation to take when a CSRF attack is found.
        /// </summary>
        /// <value>The operation to take when a CSRF attack is found.</value>
        [ConfigurationProperty(DetectionResultConfigurationKey, DefaultValue = DetectionResultDefaultValue)]
        public DetectionResult DetectionResult
        {
            get
            {
                System.Diagnostics.Debug.WriteLine(base[DetectionResultConfigurationKey]);
                return ParseDetectionResult(base[DetectionResultConfigurationKey]);
            }

            set
            {
                base[DetectionResultConfigurationKey] = value.ToString();
            }
        }

        /// <summary>
        /// Gets or sets the name of the form field used to hold the CSRF token.
        /// </summary>
        /// <value>The name of the form field used to hold the CSRF token.</value>
        [ConfigurationProperty(ErrorPageConfigurationKey)]
        public string ErrorPage
        {
            get
            {
                return (string)base[ErrorPageConfigurationKey];
            }

            set
            {
                base[FromFieldNameConfigurationKey] = value;
            }
        }

        /// <summary>
        /// Parses the detection result settings into the required enum.
        /// </summary>
        /// <param name="setting">The setting to parse.</param>
        /// <returns>A <see cref="DetectionResult"/> based on the setting provided.</returns>
        private static DetectionResult ParseDetectionResult(object setting)
        {
            DetectionResult detectionResult = DetectionResult.RaiseException;
            
            if (setting is DetectionResult)
            {
                detectionResult = (DetectionResult)setting;
            }
            else if (Enum.IsDefined(typeof(DetectionResult), setting))
            {
               detectionResult = (DetectionResult)Enum.Parse(typeof(DetectionResult), setting.ToString());
            }

            return detectionResult;
        }
    }
}
